/**
 * <copyright>
 * </copyright>
 *
 * $Id$
 */
package eistar.impl;

import java.util.Collection;

import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.InternalEObject;
import org.eclipse.emf.ecore.impl.ENotificationImpl;
import org.eclipse.emf.ecore.util.EObjectResolvingEList;

import eistar.EistarPackage;
import eistar.Entity;
import eistar.Relation;
import eistar.RelationType;

/**
 * <!-- begin-user-doc -->
 * An implementation of the model object '<em><b>Relation</b></em>'.
 * <!-- end-user-doc -->
 * <p>
 * The following features are implemented:
 * <ul>
 *   <li>{@link eistar.impl.RelationImpl#getSource <em>Source</em>}</li>
 *   <li>{@link eistar.impl.RelationImpl#getTarget <em>Target</em>}</li>
 *   <li>{@link eistar.impl.RelationImpl#getRelType <em>Rel Type</em>}</li>
 * </ul>
 * </p>
 *
 * @generated
 */
public class RelationImpl extends EntityImpl implements Relation {
	/**
	 * The cached value of the '{@link #getSource() <em>Source</em>}' reference.
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @see #getSource()
	 * @generated
	 * @ordered
	 */
	protected Entity source;

	/**
	 * The cached value of the '{@link #getTarget() <em>Target</em>}' reference list.
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @see #getTarget()
	 * @generated
	 * @ordered
	 */
	protected EList<Entity> target;

	/**
	 * The default value of the '{@link #getRelType() <em>Rel Type</em>}' attribute.
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @see #getRelType()
	 * @generated
	 * @ordered
	 */
	protected static final RelationType REL_TYPE_EDEFAULT = RelationType.DECOMPOSE;

	/**
	 * The cached value of the '{@link #getRelType() <em>Rel Type</em>}' attribute.
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @see #getRelType()
	 * @generated
	 * @ordered
	 */
	protected RelationType relType = REL_TYPE_EDEFAULT;

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	protected RelationImpl() {
		super();
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	@Override
	protected EClass eStaticClass() {
		return EistarPackage.Literals.RELATION;
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	public Entity getSource() {
		if (source != null && source.eIsProxy()) {
			InternalEObject oldSource = (InternalEObject)source;
			source = (Entity)eResolveProxy(oldSource);
			if (source != oldSource) {
				if (eNotificationRequired())
					eNotify(new ENotificationImpl(this, Notification.RESOLVE, EistarPackage.RELATION__SOURCE, oldSource, source));
			}
		}
		return source;
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	public Entity basicGetSource() {
		return source;
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	public void setSource(Entity newSource) {
		Entity oldSource = source;
		source = newSource;
		if (eNotificationRequired())
			eNotify(new ENotificationImpl(this, Notification.SET, EistarPackage.RELATION__SOURCE, oldSource, source));
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	public EList<Entity> getTarget() {
		if (target == null) {
			target = new EObjectResolvingEList<Entity>(Entity.class, this, EistarPackage.RELATION__TARGET);
		}
		return target;
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	public RelationType getRelType() {
		return relType;
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	public void setRelType(RelationType newRelType) {
		RelationType oldRelType = relType;
		relType = newRelType == null ? REL_TYPE_EDEFAULT : newRelType;
		if (eNotificationRequired())
			eNotify(new ENotificationImpl(this, Notification.SET, EistarPackage.RELATION__REL_TYPE, oldRelType, relType));
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	@Override
	public Object eGet(int featureID, boolean resolve, boolean coreType) {
		switch (featureID) {
			case EistarPackage.RELATION__SOURCE:
				if (resolve) return getSource();
				return basicGetSource();
			case EistarPackage.RELATION__TARGET:
				return getTarget();
			case EistarPackage.RELATION__REL_TYPE:
				return getRelType();
		}
		return super.eGet(featureID, resolve, coreType);
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	@SuppressWarnings("unchecked")
	@Override
	public void eSet(int featureID, Object newValue) {
		switch (featureID) {
			case EistarPackage.RELATION__SOURCE:
				setSource((Entity)newValue);
				return;
			case EistarPackage.RELATION__TARGET:
				getTarget().clear();
				getTarget().addAll((Collection<? extends Entity>)newValue);
				return;
			case EistarPackage.RELATION__REL_TYPE:
				setRelType((RelationType)newValue);
				return;
		}
		super.eSet(featureID, newValue);
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	@Override
	public void eUnset(int featureID) {
		switch (featureID) {
			case EistarPackage.RELATION__SOURCE:
				setSource((Entity)null);
				return;
			case EistarPackage.RELATION__TARGET:
				getTarget().clear();
				return;
			case EistarPackage.RELATION__REL_TYPE:
				setRelType(REL_TYPE_EDEFAULT);
				return;
		}
		super.eUnset(featureID);
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	@Override
	public boolean eIsSet(int featureID) {
		switch (featureID) {
			case EistarPackage.RELATION__SOURCE:
				return source != null;
			case EistarPackage.RELATION__TARGET:
				return target != null && !target.isEmpty();
			case EistarPackage.RELATION__REL_TYPE:
				return relType != REL_TYPE_EDEFAULT;
		}
		return super.eIsSet(featureID);
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated NOT
	 */
	@Override
	public String toString() {
		if (eIsProxy()) return super.toString();

		StringBuffer result = new StringBuffer();
		result.append(String.format("(%s) %s ", name, getSource().getName()));
		result.append(relType);
		for(Entity target: getTarget())
			result.append(String.format(" %s", target.getName()));
		return result.toString();
	}
	
	@Override
	public int compareTo(Entity o) {
		int result = super.compareTo(o);
		if (result != 0 && o instanceof Relation ) {
			Relation rel = (Relation) (o.eIsProxy() ? eResolveProxy((InternalEObject) o) : o);
			
			if (this.eIsProxy())
				return ((Entity)eResolveProxy(this)).compareTo(rel);
			
			result = (getSource() != null && rel.getSource() != null) ? getSource().compareTo(rel.getSource()) : result;
			for (int i = 0; i < target.size() && result == 0; i++)
				result = i > rel.getTarget().size() ?
						1 :  target.get(i).compareTo(rel.getTarget().get(i));
		}
		return result;
	}
	
	/**
	 * @generated NOT
	 */
	@Override
	public boolean isReferredTo(Entity entity, int role) {
		if (entity.eIsProxy())
			entity = (Entity) eResolveProxy((InternalEObject) entity);
		
		boolean result = ((role & SOURCE) > 0) && getSource().equals(entity);
		if (!result && (role & TARGET) > 0 )
			for (int i = 0; i < target.size() && !result; i++) {
				Entity t = target.get(i);
				if (t.eIsProxy())
					t = (Entity) eResolveProxy((InternalEObject) t);
				result = t.equals(entity);
			}
		
		return result;
	}
} //RelationImpl
